package com.oswift.utils.http;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * HTTP请求工具类，用于发送HTTP请求，并获取相应内容。
 *
 * @author zhuou
 * @version C03 Oct 27, 2012
 * @since OSwift GPM V1.0
 */
public final class HttpUtil
{
    /**
     * HTTP请求方法: POST
     */
    public static final String POST_METHOD = "POST";

    /**
     * HTTP请求方法: GET
     */
    public static final String GET_METHOD = "GET";

    /**
     * 日志实例
     */
    private static Logger log = LoggerFactory.getLogger(HttpUtil.class);

    private static final String NEW_LINE = "\r\n";

    private static final String CONTAIN_SYMBOL = "&";

    private static final String EQUAL_SYMBOL = "=";

    // 超时时间
    private static final String CONNECT_TIMEOUT = "20000";

    private static final String ENCODING = "UTF-8";

    private HttpUtil()
    {
    }

    /**
     * 发送HTTP请求
     *
     * @param urlString
     *            HTTP请求URL
     * @param method
     *            HTTP请求方法
     * @param parameters
     *            HTTP请求参数
     * @param properties
     *            HTTP请求附件挑起，作为互相功能的扩展
     * @param type
     *            当请求为METHOD为POST时:
     *            type=1,则代表参数parameters体现在url中，即http://XXXXXXXXX
     *            /?param1=12&param2=23 type=2,则代表参数parameters体现在请求消息体中。
     * @return 响应对象
     * @throws IOException
     *             IO异常
     */
    public static String send(String urlString, String method,
            Map<String, String> parameters, Map<String, String> properties,
            String type) throws IOException
    {
        // GET请求
        if (GET_METHOD.equalsIgnoreCase(method))
        {
            return sendGetRequest(urlString, parameters, properties);
        }
        // POST请求
        if (POST_METHOD.equalsIgnoreCase(method))
        {
            return sendPostRequest(urlString, parameters, properties, type);
        }
        return null;
    }

    /**
     * 发送HTTP请求
     *
     * @param urlString
     *            HTTP请求URL
     * @param method
     *            HTTP请求方法
     * @param properties
     *            HTTP请求附件挑起，作为互相功能的扩展
     * @return 响应对象
     * @throws IOException
     *             IO异常
     */
    public static Map<String, String> sendByHeader(String urlString,
            String method, Map<String, String> properties) throws IOException
    {
        // 发送请求
        if (POST_METHOD.equalsIgnoreCase(method)
                || GET_METHOD.equalsIgnoreCase(method))
        {
            return sendRequestByHeader(urlString, method, properties);
        }
        return null;
    }

    /**
     *
     * 发送HTTP Get请求
     *
     * @param urlString
     *            请求URL
     * @param parameters
     *            请求参数
     * @param properties
     *            HTTP请求附件挑起，作为互相功能的扩展
     * @return
     * @throws IOException
     */
    private static String sendGetRequest(String urlString,
            Map<String, String> parameters, Map<String, String> properties)
        throws IOException
    {
        // 如果有参数，拼装完整的URL
        if (null != parameters && !parameters.isEmpty())
        {
            StringBuffer param = new StringBuffer();
            param.append('?');

            for (Map.Entry<String, String> entry : parameters.entrySet())
            {
                param.append(entry.getKey()).append(EQUAL_SYMBOL).append(
                        entry.getValue()).append(CONTAIN_SYMBOL);
            }
            // 拼装完整的URL，并去掉最后一个&符号
            urlString += param.substring(0, param.length() - 1);
        }
        HttpURLConnection urlConnection = null;

        try
        {
            URL url = new URL(urlString);
            urlConnection = (HttpURLConnection) url.openConnection();

            // 设置超时时间20秒
            urlConnection.setConnectTimeout(Integer.valueOf(CONNECT_TIMEOUT));

            urlConnection.setRequestMethod(GET_METHOD);
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setUseCaches(false);
            if (properties != null)
            {
                for (Map.Entry<String, String> entry : properties.entrySet())
                {
                    urlConnection.addRequestProperty(entry.getKey(), entry
                            .getValue());
                }
            }
        }
        catch (IOException e)
        {
            log.error("Fail to send http request. URL:" + urlString, e);
            throw e;
        }
        return getContent(urlString, urlConnection);
    }

    /**
     *
     * 发送HTTP Post请求
     *
     * @param urlString
     *            请求URL
     * @param parameters
     *            请求参数
     * @param properties
     *            HTTP请求附件挑起，作为互相功能的扩展
     * @param type
     *            当请求为METHOD为POST时:
     *            type=1,则代表参数parameters体现在url中，即http://XXXXXXXXX
     *            /?param1=12&param2=23 type=2,则代表参数parameters体现在请求消息体中。
     * @return
     * @throws IOException
     */
    private static String sendPostRequest(String urlString,
            Map<String, String> parameters, Map<String, String> properties,
            String type) throws IOException
    {
        HttpURLConnection urlConnection = null;
        OutputStream out = null;

        try
        {
            URL url = new URL(urlString);
            urlConnection = (HttpURLConnection) url.openConnection();

            // 设置超时时间20秒
            urlConnection.setConnectTimeout(Integer.valueOf(CONNECT_TIMEOUT));

            urlConnection.setRequestMethod(POST_METHOD);
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setUseCaches(false);

            if (properties != null)
            {
                for (Map.Entry<String, String> entry : properties.entrySet())
                {
                    urlConnection.addRequestProperty(entry.getKey(), entry
                            .getValue());
                }
            }
            if (parameters != null && !parameters.isEmpty())
            {
                StringBuffer param = new StringBuffer();

                if ("1".equals(type))
                {
                    for (Map.Entry<String, String> entry : parameters
                            .entrySet())
                    {
                        param.append(entry.getKey()).append(EQUAL_SYMBOL)
                                .append(entry.getValue());
                        param.append(CONTAIN_SYMBOL);
                    }
                }
                else if ("2".equals(type))
                {
                    for (Map.Entry<String, String> entry : parameters
                            .entrySet())
                    {
                        param.append(entry.getValue());
                    }
                }

                out = urlConnection.getOutputStream();
                out.write(param.toString().getBytes());
                urlConnection.getOutputStream().flush();
            }
        }
        catch (IOException e)
        {
            log.error("Fail to send http request. URL:" + urlString, e);
            throw e;
        }
        finally
        {
            try
            {
                if (out != null)
                {
                    out.close();
                }

            }
            catch (IOException e1)
            {
                // 忽略异常
                log.warn("Close outputstream failed.");
            }
        }

        return getContent(urlString, urlConnection);
    }

    /**
     *
     * 发送HTTP请求 参数放在消息头中
     *
     * @param urlString
     *            请求URL
     * @param method
     *            请求方法
     * @param properties
     *            HTTP请求附件挑起，作为互相功能的扩展
     * @return Map<String,String>
     * @throws IOException
     */
    private static Map<String, String> sendRequestByHeader(String urlString,
            String method, Map<String, String> properties) throws IOException
    {
        HttpURLConnection urlConnection = null;

        try
        {
            URL url = new URL(urlString);
            urlConnection = (HttpURLConnection) url.openConnection();

            // 设置超时时间20秒
            urlConnection.setConnectTimeout(Integer.valueOf(CONNECT_TIMEOUT));
            if (POST_METHOD.equalsIgnoreCase(method))
            {
                urlConnection.setRequestMethod(POST_METHOD);
            }
            else if (GET_METHOD.equalsIgnoreCase(method))
            {
                urlConnection.setRequestMethod(GET_METHOD);
            }

            urlConnection.setUseCaches(false);

            if (properties != null)
            {
                for (Map.Entry<String, String> entry : properties.entrySet())
                {
                    urlConnection.addRequestProperty(entry.getKey(), entry
                            .getValue());
                }
            }

        }
        catch (IOException e)
        {
            log.error("Fail to send http request. URL:" + urlString, e);
            throw e;
        }

        return getResponseHeader(urlString, urlConnection);
    }

    /**
     * 得到响应消息头字段
     *
     * @param urlConnection
     * @return 响应对象
     * @throws IOException
     */
    private static Map<String, String> getResponseHeader(String urlString,
            HttpURLConnection urlConnection) throws IOException
    {
        Map<String, String> respHeader = new HashMap<String, String>();

        // 将返回码及响应头字段放入map中
        try
        {
            String returnCode = String.valueOf(urlConnection.getResponseCode());
            Map<String, List<String>> properties = urlConnection
                    .getHeaderFields();
            respHeader.put("returnCode", returnCode);

            if (properties != null)
            {
                for (Map.Entry<String, List<String>> entry : properties
                        .entrySet())
                {
                    StringBuffer temp = new StringBuffer();
                    List<String> list = entry.getValue();
                    Iterator<String> iter = list.iterator();

                    while (iter.hasNext())
                    {
                        temp.append(iter.next() + ",");
                    }

                    String value = temp.substring(0, temp.length() - 1);
                    respHeader.put(entry.getKey(), value);
                }
            }
        }
        catch (IOException e)
        {
            log.error("Fail to get value from response of Http. URL:"
                    + urlString, e);
            throw e;
        }
        finally
        {
            if (urlConnection != null)
            {
                urlConnection.disconnect();
            }
        }

        return respHeader;
    }

    /**
     * 得到响应对象
     *
     * @param urlConnection
     * @return 响应对象
     * @throws IOException
     */
    private static String getContent(String urlString,
            HttpURLConnection urlConnection) throws IOException
    {
        InputStream in = null;
        BufferedReader bufferedReader = null;

        String content = null;

        try
        {
            in = urlConnection.getInputStream();
            bufferedReader = new BufferedReader(new InputStreamReader(in));
            StringBuffer temp = new StringBuffer();
            String line = bufferedReader.readLine();
            while (line != null)
            {
                temp.append(line).append(NEW_LINE);
                line = bufferedReader.readLine();
            }

            // 获取编码格式，如果HTTP返回编码格式不存在，则默认为UTF-8
            String ecod = urlConnection.getContentEncoding();

            if (ecod == null)
            {
                ecod = ENCODING;
            }

            content = new String(temp.toString().getBytes(), ecod);

        }
        catch (IOException e)
        {
            log.error("Fail to get value from response of Http. URL:"
                    + urlString, e);
            throw e;
        }
        finally
        {
            release(urlConnection, in, bufferedReader);
        }

        return content;
    }

    /**
     * 释放内存资源
     *
     * @param urlConnection
     * @param in
     * @param bufferedReader
     */
    private static void release(HttpURLConnection urlConnection,
            InputStream in, BufferedReader bufferedReader)
    {
        if (urlConnection != null)
        {
            urlConnection.disconnect();
        }

        try
        {
            if (bufferedReader != null)
            {
                bufferedReader.close();
            }

            if (in != null)
            {
                in.close();
            }
        }
        catch (IOException e)
        {
            // 忽略异常
            log.warn("Close inputstream failed.");
        }
    }

}
